// DHTMLHandler.cpp // d.g.gilbert #include "Dvibrant.h" #include "DFile.h" #include "DRichProcess.h" #include "DRichViewNu.h" #include "DHTMLHandler.h" #include "DHTMLprocess.h" #include "rtfchars.h" #include "DRichMoreStyle.h" class DHTMLsetup { public: DHTMLsetup(); }; static DHTMLsetup* gHTMLsetup = NULL; #if 0 static DHTMLsetup theSetup; // construct it now ! #endif DHTMLsetup::DHTMLsetup() { DHTMLprocess::InitKeys(); //ReadOutputMap("gen", gGenCharMap); //gOutMap= gGenCharMap; //// //DRichprocess::gGenCharMap= DRichprocess::ReadOutputMap("gen"); //DRichprocess::gSymCharMap= DRichprocess::ReadOutputMap("sym"); gHTMLsetup = this; } //class DHTMLHandler char* DHTMLHandler::IsRich(char* buf, ulong buflen) { // HTML doesn't have a fixed magic string -- usage is variable // some diagnostic strings (all case-insensitive) // // // uncertain: </ <a // href= char* cp, *atbuf= buf; if (buflen==0) buflen= StrLen(buf); ulong len = buflen; while (len>3) { cp= (char*) MemChr(atbuf,'<',len); if (cp) { if (cp[1] == '/' && (cp[2] == 'a' || cp[2] == 'A') && cp[3] == '>') return buf; else if (!StrNICmp( cp, "<html>", 6)) return buf; else if (!StrNICmp( cp, "<head>", 6)) return buf; else if (!StrNICmp( cp, "<title>", 7)) return buf; else if (!StrNICmp( cp, "<p>", 3)) return buf; // ?? weak test but need else if (!StrNICmp( cp, "<a href=", 9)) return buf; //if (!StrNICmp( cp, "<a ", 3)) { // unsigned long at; // if (Nlm_StrngPos( cp, "</a>", 3, false, &at)) return true; // } cp++; len -= (cp - atbuf); atbuf = cp; } else return NULL; } return NULL; } DHTMLHandler::DHTMLHandler( DRichView* itsDoc, DFile* savefile) : DRichHandler( itsDoc, savefile) { fFormatName = "HTML"; fMinDataToProcess= 128; // no fixed min, need to look at data... if (!gHTMLsetup) gHTMLsetup= new DHTMLsetup(); } DHTMLHandler::~DHTMLHandler() { } DRichprocess* DHTMLHandler::NewProcessor( DFile* itsFile, Nlm_MonitorPtr progress) { fProcessor = new DHTMLprocess( itsFile, fDoc, progress); return fProcessor; } Boolean DHTMLHandler::ProcessData( char* cbeg, char* cend, Boolean endOfData, ulong& dataRemaining) { char * cp; fcsave= 0; fclen= cend - cbeg; // + 1; cp= cend; if (!endOfData) { if ((fclen==0) || ( fProcessStage == kAtStart && fclen<fMinDataToProcess)) return false; // scan for last newline and stop there !! #if 1 //TEST w/out << NEED THIS for at least some while (cp - cbeg > fLastScanto && !(*cp == '\n' || *cp == '\r')) cp--; if (cp < cend && (*cp == '\n' || *cp == '\r')) cp++; #endif } #if 1 //TEST w/out << NEED THIS for at least some if (cp - cbeg <= fLastScanto) { fLastScanto= cend - cbeg; if (!endOfData) return false; // !??! don't process line w/o end else cp= cend; } #endif #if 0 // bad nulls ?? if (*cp) cp++; fcsave= *cp; *cp= 0; #endif fclen= cp - cbeg; // + 1; if (fclen && fDocFile) { if (cbeg[fclen-1] == 0) fclen--; //?? fDocFile->WriteData( cbeg, fclen); } return this->ProcessData2( cp, cbeg, cend, endOfData, dataRemaining); } // class DHTMLprocess //static char gGenCharMap[rtfSC_MaxChar]; //static char * gOutMap = gGenCharMap; DHTMLprocess::DHTMLprocess( DFile* itsFile, DRichView* itsDoc, Nlm_MonitorPtr progress) : DRichprocess( itsFile, itsDoc, progress), fStop(0), fTokenLen(0), fListType(0), fListNum(0), fDLStyle(0), fQuote(0), fCurControl(0), fCurField(0), fLastField(0), fPicLink(0), fAnchorLink(0), fURLstore(NULL), fNamestore(NULL), fFormURL(NULL), fGoplusStore(NULL), fMethodstore(NULL), fValstore(NULL), fTypestore(NULL), fOptionstore(NULL), fSizestore(NULL),fMaxlengthstore(NULL),fRowsstore(NULL),fColsstore(NULL), fPushSize(0), fPushBuf(NULL), fPushBufstore(NULL), fInHead(true), fInParam(false), fInForm(false), fInControl(false), fIsMap(false), fIsChecked(false), fSelectitem(0), fCurItem(0), fIsMultiple(false), fTurnOn(true), fIsIndex(false), fPreformat(false) { //fOutMap= DRichprocess::gGenCharMap; } DHTMLprocess::~DHTMLprocess() { MemFree(fURLstore); MemFree(fNamestore); MemFree(fMethodstore); MemFree(fGoplusStore); MemFree(fFormURL); MemFree(fValstore); MemFree(fTypestore); MemFree(fOptionstore); MemFree(fPushBufstore); MemFree(fSizestore); MemFree(fMaxlengthstore); MemFree(fRowsstore); MemFree(fColsstore); } //static short DHTMLprocess::Hash( char *s) { char c; short val = 0; while ((c = *s++) != '\0') val += (int) tolower(c); return (val); } //static void DHTMLprocess::InitKeys() { HTMLKey *rp; for (rp = htmlKeys; rp->htmlKStr != NULL; rp++) { rp->htmlKHash = Hash(rp->htmlKStr); } for (rp = htmlAmperChars; rp->htmlKStr != NULL; rp++) { rp->htmlKHash = Hash(rp->htmlKStr); } } void DHTMLprocess::Lookup( char *s, HTMLKey* keyset) { HTMLKey *rp; short hash; #ifdef COMP_BOR /* ?? dgg */ int LIBCALL (*cmp)(const char*,const char*); #else #ifdef COMP_SYMC int (* LIBCALL cmp)(const char*, const char*); #else int (*cmp)(const char*,const char*); #endif #endif if (keyset == htmlAmperChars) cmp= Nlm_StringCmp; else cmp= Nlm_StringICmp; fClass = tokUnknown; if (*s == 0) return; hash = Hash(s); for (rp = keyset; rp->htmlKStr != NULL; rp++) { if (hash == rp->htmlKHash && cmp(s, rp->htmlKStr) == 0) { fClass = tokControl; fMajor = rp->htmlKMajor; fMinor = rp->htmlKMinor; fStop = rp->htmlKStop; return; } } } void DHTMLprocess::Pushback(char c) // private { if (c != EOF) { fPushedChar = c; } } enum { kGotNone = 0, kGotToken, kGotParam }; short DHTMLprocess::GotTokenOrParam() // private { if (fTokenLen>0) { // need to process last token ! fTokenBuf[fTokenLen] = '\0'; long i, tokenlen= fTokenLen; fTokenLen= 0; if (fInParam) { switch (fCurField) { case htmlIsMap: fIsMap= true; break; case htmlAction: case htmlImageSrc: case htmlHref: for (i=0; i<tokenlen; i++) if (fTokenBuf[i]<' ') fTokenBuf[i]= ' '; MemFree(fURLstore); fURLstore= StrDup(fTokenBuf); break; //case htmlInput: //case htmlSelect: //case htmlTextarea: // form tags -- stuff data where ?? case htmlTitle: case htmlName: MemFree(fNamestore); fNamestore= StrDup(fTokenBuf); break; case htmlMethod: MemFree(fMethodstore); fMethodstore= StrDup(fTokenBuf); break; case htmlValue: MemFree(fValstore); fValstore= StrDup(fTokenBuf); if (fLastField==htmlOption) fCurField= fLastField; break; case htmlType: MemFree(fTypestore); fTypestore= StrDup(fTokenBuf); break; case htmlChecked: fIsChecked= true; break; case htmlSelected: fSelectitem= fCurItem; break; case htmlMultiple: fIsMultiple= true; break; case htmlSize: MemFree(fSizestore); fSizestore= StrDup(fTokenBuf); break; case htmlMaxlength: MemFree(fMaxlengthstore); fMaxlengthstore= StrDup(fTokenBuf); break; case htmlRows: MemFree(fRowsstore); fRowsstore= StrDup(fTokenBuf); break; case htmlCols: MemFree(fColsstore); fColsstore= StrDup(fTokenBuf); break; case htmlOption: fTokenBuf[tokenlen++]= '\t'; fTokenBuf[tokenlen]= '\0'; if (!fOptionstore) fOptionstore= StrDup(fTokenBuf); else StrExtendCat( &fOptionstore, fTokenBuf); // need to collect BOTH option text and values ! if (fValstore) { tokenlen= StrLen( fValstore); StrCpy( fTokenBuf, fValstore); } else tokenlen= 0; fTokenBuf[tokenlen++]= '\t'; fTokenBuf[tokenlen]= '\0'; if (!fRowsstore) fRowsstore= StrDup(fTokenBuf); else StrExtendCat( &fRowsstore, fTokenBuf); break; } fInParam= false; return kGotParam; } else { Lookup( fTokenBuf, htmlKeys); // sets class, major, minor return kGotToken; } } else return kGotNone; } void DHTMLprocess::GetToken1() // private { short c; fClass = tokUnknown; // initialize token vars fParam = tokNoParam; if (fPushedChar != EOF) { c = fPushedChar; fPushedChar = EOF; } else c= GetOneChar(); switch ( c ) { case EOF: fClass = tokEOF; fMajor = tokEOF; return; case tokBreakInData: fClass= tokEOF; fMajor= tokBreakInData; return; case '>': { if (fInControl && fQuote) goto cInQuote; if (!fInControl) goto cHandleText; if (GotTokenOrParam() != kGotNone) { Pushback(c); return; } if (fCurField == htmlOption) { // fCurControl == htmlSelect && Pushback('='); // turn following text into option Param... return; } fInControl= false; fClass = tokControl; fMajor = htmlEndControl; fMinor = -1; return; } case '<': if (fInControl && fQuote) goto cInQuote; if (fQuote == (char)234) { // kInFormText fInControl= false; this->handleLinkAttr( fCurControl); } fInControl= true; fTurnOn= true; fInParam= false; fQuote= 0; fCurControl= 0; fCurField= 0; fTokenLen= 0; fPicLink= 0; //fAnchorLink= 0; fClass = tokDropchar; return; default: if (fInControl) { cInQuote: // !! need to deal with complex options in <Control ... > syntax // e.g. <a href="some.string" name="some.string" etc. > text here </a> // e.g. < IMG SRC ="triangle.gif" ALT="Warning:"> text here... // < A HREF="Go">< IMG SRC ="Button"> Press to start</A> if ( (fQuote && c != fQuote) || (fInParam && c != fQuote && c != '"' && c != '\'' && c > ' ') || isalnum(c) ) { // store in token buf until unquoted if (fTokenLen<kMaxTokenBuf) fTokenBuf[fTokenLen++] = c; if (fQuote == (char)234) { // kInFormText goto labelNoControl; // also stuff c into texthandler stream } else fClass = tokDropchar; return; } if (GotTokenOrParam() == kGotToken) { Pushback( c); // ! need to handle terminator char return; } if (fQuote && c == fQuote) { // must be sure we handle unquote ! after storing param fQuote = 0; fClass = tokDropchar; return; } switch ( c ) { case '/': fTurnOn= false; break; case '=': fInParam= true; break; case '"': case '\'': // ?? these may be good only if (fInParam) ??? if (fQuote) fQuote= 0; // end of quote.. else fQuote= c; break; default: //if (isspace(c)) break; break; } fClass = tokDropchar; return; } else { labelNoControl: switch ( c ) { case '&': //wordat= fTokenBuf+fTokenLen; fTokenLen= 0; do { c = GetOneChar(); if (fTokenLen<kMaxTokenBuf) fTokenBuf[fTokenLen++] = c; } while (c > EOF && isalnum(c)); fTokenBuf[fTokenLen] = '\0'; Lookup( fTokenBuf, htmlAmperChars); // sets class, major, minor return; case '\t': fClass = tokControl; fMajor = htmlSpecialChar; fMinor = htmlTab; return; case '\r': case '\n': //NEWLINE: if (fPreformat) { fClass = tokControl; fMajor = htmlSpecialChar; fMinor = htmlNewline; } else if (fTextSize>0) { // messy fix for that cutesy horizontal bar if ( fTextSize > 15 && fText[15] == '_' && fText[1] == '_' && fText[fTextSize-2] == '_') { fTextSize= 0; handleSpecialChar( htmlHBar); fClass = tokDropchar; } else // put space in, if this isn't new parag goto cHandleSpace; } else fClass = tokDropchar; return; case ' ': cHandleSpace: if (fPreformat || fLastChar != ' ') { fClass = tokText; fMajor = ' '; fMinor = ' '; // MapChar( c); } else fClass = tokDropchar; return; case '\0': fClass = tokDropchar; return; default: cHandleText: fClass = tokText; fMajor = c; fMinor = c; // MapChar( c); return; } } } } short DHTMLprocess::GetOneChar() { #if 1 if (fPushSize && fPushBuf) { short c= (unsigned char) *fPushBuf; // must be unsigned !! fPushSize--; fPushBuf++; return c; } else return DRichprocess::GetOneChar(); #else short c; if (fDataBuffer) { c= (unsigned char) *fDataBuffer; // must be unsigned !! if (fDataSize) { // for counted data fDataSize--; fDataBuffer++; if (!fDataSize) fDataBuffer= NULL; // so EOF next time } else if (c) fDataBuffer++; // for null-term data else if (!fEndOfData) c= tokBreakInData; else c= EOF; } else if (fDataFile) c = fgetc( fDataFile->fFile); else { if (!fEndOfData) c= tokBreakInData; else c= EOF; } return (c); #endif } void DHTMLprocess::handleTextClass() { if (IsNewStyle()) StoreStyle(fOldStyleRec.style, FALSE); if (fMinor != rtfSC_nothing) PutStdChar(fMinor); else { char buf[128]; if (fMajor < 128) /* in ASCII range */ sprintf (buf, "[[%c]]", fMajor); else sprintf (buf, "[[\\'%02x]]", fMajor); PutLitStr (buf); } fLastChar= fMajor; } void DHTMLprocess::handleControlClass() { switch (fMajor) { case htmlDocAttr : handleDocAttr(fMinor); break; case htmlLinkAttr : handleLinkAttr(fMinor); break; case htmlFormAttr : handleFormAttr(fMinor); break; case htmlCharAttr : handleCharAttr(fMinor); break; case htmlParAttr : handleParAttr(fMinor); break; case htmlListAttr : handleListAttr(fMinor); break; case htmlPictAttr : handlePictAttr(fMinor); break; case htmlSpecialChar: handleSpecialChar(fMinor); break; case htmlEndControl: handleEndControl(fMinor); break; } } void DHTMLprocess::handleEndControl(short attr) { // e.g, > end of any control if (fCurControl == htmlForm || fCurControl == htmlInput //|| fCurControl == htmlSelect //|| fCurControl == htmlTextarea ) { // call here AFTER DNetHTMLprocess::handleEndControl this->handleFormAttr( fCurControl); //?? !? why this mess here } else if (fCurControl == htmlImage) { short kind; char * dummypict = (char*) MemNew( 1); *dummypict= 0; if (fAnchorLink) kind= DPictStyle::kPictNetLink; else kind= DPictStyle::kPictNetPic; DPictStyle* thePic= new DPictStyle( kind, dummypict, 1, true); if (!fParaCount) NewParagraph(); if (fPicLink) { Nlm_RecT loc; Nlm_LoadRect( &loc, 0, 0, 35, 22); // top is to fetch picture thePic->AddLink( DPictStyle::kPictNetPic, fPicLink, loc); if (fAnchorLink) { Nlm_LoadRect( &loc, 0, 23, 35, 35); // bottom is to fetch link info thePic->AddLink( DPictStyle::kPictNetLink, fAnchorLink, loc); } fPicLink= 0; } // !? in html, is damn url suffix supposed indicate TYPE of data !? // or can we assume all these are GIF pictures ? fStyleRec.style.ismap= fIsMap; StoreStyleObject( thePic, 35, 35); } fCurControl= 0; fCurField= 0; fIsMap= false; } void DHTMLprocess::handleDocAttr(short attr) { switch (attr) { case htmlHTML: if (fTurnOn) fCurControl= attr; break; case htmlHead: fInHead= fTurnOn; break; case htmlBody: fInHead= false; break; case htmlTitle: // ! this htmlTitle can occur both in Head and Body/Anchor if (fTurnOn) { fCurControl= attr; //?? fNamestore= (char*) MemFree(fNamestore); } else { #if 0 fTitle= fNamestore; fNamestore= NULL; #else if (fTextSize) { // fInHead && MemFree(fTitle); fText[fTextSize]= '\0'; fTitle= StrDup( fText); fTextSize= 0; } #endif } break; case htmlIsIndex: { fIsIndex= true; MemFree(fPushBufstore); fPushBufstore= StrDup(" <A HREF=?>Click here to query</A> "); fPushBuf= fPushBufstore; fPushSize= StrLen(fPushBuf); //MemFree(fURLstore); //fURLstore= StrDup("#"); // entire doc is somehow flagged as a query document, and need // some kind of button to send query to server from this doc !? // go->fType= kTypeQuery; } break; case htmlBase: break; case htmlLink: case htmlNextID: break; //case htmlHref: // !! bug in processing tokens -- arrive here after finding Link/HREF ! } } #if 0 /////////// html forms stuff /////////////// ///// convert to gopher ask forms /////////// <form action="partial-url-to-handle-data" method=get or post> <input name="variable_name"> // one line text input (type=text) <input type=text name="variable_name" value='default text'> // one line text input >> Ask: variable_name:\t default text <input type=password name="variable_name-name"> // one line password text input >> AskP: variable_name <input type=submit value='button title'> // button to send form >> default ask form "okay" button <input type=reset value='button title'> // button to clear current choices >> no ask equivalent <input type=checkbox name=variable_name value="box title" checked> >> Select: box title:0 or 1 <input type=radio name=var_name value='title 1'> <input type=radio name=var_name value='title 2'> >> Choose: var_name: \t title 1 \t title 2 ... <textarea name=var_name cols=40 rows=2> // text input box default text </textarea> >> AskL: var_name \t default text <select> <option selected> name1 <option> name2 <option value=n3> name2 </select> >> Choose: var_name: \t name1 \t name2 ... </form> // forms tags htmlLinkAttr, htmlForm, "form", kSlashStop, 0, htmlLinkAttr, htmlInput, "input", kNoStop, 0, htmlLinkAttr, htmlSelect, "select", kSlashStop, 0, htmlLinkAttr, htmlTextarea, "textarea", kSlashStop, 0, htmlLinkAttr, htmlValue, "value", kNoStop, 0, htmlLinkAttr, htmlType, "type", kNoStop, 0, htmlLinkAttr, htmlOption, "option", kNoStop, 0, htmlLinkAttr, htmlAction, "action", kNoStop, 0, htmlLinkAttr, htmlMethod, "method", kNoStop, 0, #endif void DHTMLprocess::handleFormAttr(short attr) { char buf[512]; DWindow* fWin; DControlStyle* cs; switch (attr) { case htmlForm: fCurControl= attr; fCurField= attr; fInForm= fTurnOn; if (fInForm) { if (fInControl) { fURLstore= (char*) MemFree(fURLstore); fMethodstore= (char*) MemFree(fMethodstore); fFormURL= (char*) MemFree(fFormURL); //fGoplusStore= (char*) MemFree(fGoplusStore); //fGoplusStore= StrDup("+ASKHTML:\n"); PushStyle(); fIsChecked= fIsMultiple= false; fSelectitem= 0; } else { // <FORM METHOD=get/post/localexec ACTION="proto://path/function opts"> cs = NULL; fWin= fDoc->GetWindow(); cs= new DHiddenCStyle( fWin); if (!fMethodstore) cs->ControlData( "GET", fURLstore); else cs->ControlData( fMethodstore, fURLstore); cs->Install(); StoreStyleObject( cs, cs->Width(), cs->Height()); } } else { //fStyleRec.style.color= 0; // ?? //fStyleRec.style.linkid= 0; //PopStyle(); } break; // need to collect other Forms control tags: // input: TYPE= NAME= VALUE= CHECKED SIZE= MAXLENGTH= // option: VALUE= (or value after ">") SELECTED // select: NAME= SIZE= (#items to show) MULTIPLE // textarea: NAME= COLS= ROWS= case htmlInput: if (fInControl) { fCurControl= attr; //?? fCurField= attr; fTypestore= (char*) MemFree(fTypestore); fNamestore= (char*) MemFree(fNamestore); fMethodstore= (char*) MemFree(fMethodstore); fOptionstore= (char*) MemFree(fOptionstore); fValstore= (char*) MemFree(fValstore); fSizestore= (char*) MemFree(fSizestore); fMaxlengthstore= (char*) MemFree(fMaxlengthstore); fRowsstore= (char*) MemFree(fRowsstore); fColsstore= (char*) MemFree(fColsstore); fIsChecked= fIsMultiple= false; fSelectitem= 0; } else { // this are HandleEndControl, e.g., at "...>", methods, // not !fInControl start methods (e.g., at "</control..." cs = NULL; fWin= fDoc->GetWindow(); if (!fTypestore || StrICmp( fTypestore, "text")==0) { // <input type=text name="variable_name" value='default text' size=10> cs= new DEditTextCStyle( fWin); if (fSizestore) cs->fWidth= atol(fSizestore); else if (fMaxlengthstore) cs->fWidth= atol(fMaxlengthstore); cs->ControlData( fNamestore, fValstore); // installs in view !? } else if (StrICmp( fTypestore, "password")==0) { // <input type=password name="variable_name"> cs= new DPasswordCStyle( fWin); if (fSizestore) cs->fWidth= atol(fSizestore); else if (fMaxlengthstore) cs->fWidth= atol(fMaxlengthstore); cs->ControlData( fNamestore, fValstore); // installs in view !? } else if (StrICmp( fTypestore, "hidden")==0) { // <input type=hidden name="variable_name" value="whatever"> cs= new DHiddenCStyle( fWin); cs->ControlData( fNamestore, fValstore); } else if (StrICmp( fTypestore, "submit")==0) { // <input type=submit value='button title'> // button to send form cs= new DDefaultButtonCStyle( fWin); if (!fValstore) cs->ControlData( fNamestore, "Submit"); else cs->ControlData( fNamestore, fValstore); } else if (StrICmp( fTypestore, "reset")==0) { // <input type=reset value='button title'> // button to clear current choices cs= new DButtonCStyle( fWin); if (!fValstore) cs->ControlData( fNamestore, "Reset"); else cs->ControlData( fNamestore, fValstore); } else if (StrICmp( fTypestore, "checkbox")==0) { //<input type=checkbox name=variable_name value="box title" checked> cs= new DCheckboxCStyle( fWin); cs->fSelected= fIsChecked; if (!fValstore) cs->ControlData( fNamestore, "on"); else cs->ControlData( fNamestore, fValstore); } else if (StrICmp( fTypestore, "radio")==0) { //<input type=radio name=var_name value='title 2'> cs= new DRadioCStyle( fWin); cs->fSelected= fIsChecked; if (!fValstore) cs->ControlData( fNamestore, "on"); else cs->ControlData( fNamestore, fValstore); } else if (StrICmp( fTypestore, "file")==0) { //<input type=file name=default_file_name value='anything'> cs= new DFileCStyle( fWin); if (!fValstore) cs->ControlData( fNamestore, "default-file"); else cs->ControlData( fNamestore, fValstore); } if (cs) { cs->Install(); StoreStyleObject( cs, cs->Width(), cs->Height()); } } break; case htmlSelect: //<select name="myname"> //<option selected> name1 //<option> name2 //<option value=n3> name3 //</select> if (fTurnOn) { // fInControl fCurControl= attr; //?? fCurField= attr; fCurItem= 0; fLastField= 0; //fSomething= fTurnOn; fNamestore= (char*) MemFree(fNamestore); fOptionstore= (char*) MemFree(fOptionstore); fValstore= (char*) MemFree(fValstore); fSizestore= (char*) MemFree(fSizestore); fMaxlengthstore= (char*) MemFree(fMaxlengthstore); fRowsstore= (char*) MemFree(fRowsstore); fColsstore= (char*) MemFree(fColsstore); fIsChecked= fIsMultiple= false; fSelectitem= 0; } else { fLastField= 0; cs = NULL; fWin= fDoc->GetWindow(); cs= new DPopupCStyle( fWin); // ! need to options == popup selections -> from fOptionstore cs->fSelected= fSelectitem; cs->ControlData( fNamestore, fOptionstore, fRowsstore); //? fOption not fValstore cs->Install(); StoreStyleObject( cs, cs->Width(), cs->Height()); } break; case htmlOption: if (fInControl) { fCurField= attr; fCurItem++; fValstore= (char*) MemFree(fValstore); } else { fLastField= 0; } break; case htmlTextarea: //<textarea name=var_name cols=40 rows=2> //default text //</textarea> if (fTurnOn) { // fInControl) fCurControl= attr; //?? fCurField= attr; //fSomething= fTurnOn; fNamestore= (char*) MemFree(fNamestore); fValstore= (char*) MemFree(fValstore); fSizestore= (char*) MemFree(fSizestore); fMaxlengthstore= (char*) MemFree(fMaxlengthstore); fRowsstore= (char*) MemFree(fRowsstore); fColsstore= (char*) MemFree(fColsstore); fIsChecked= fIsMultiple= false; fSelectitem= 0; } else { cs = NULL; fWin= fDoc->GetWindow(); cs= new DDialogTextCStyle( fWin); cs->ControlData( fNamestore, fValstore); if (fColsstore) cs->fWidth= atol(fColsstore); // # chars wide if (fRowsstore) cs->fHeight= atol(fRowsstore); // # chars tall cs->Install(); StoreStyleObject( cs, cs->Width(), cs->Height()); } break; case htmlMethod: fCurField= attr; // this is GET or POST -- only those two? break; case htmlAction: fCurField= attr; fURLstore= (char*) MemFree(fURLstore); break; case htmlChecked: fIsChecked= true; fCurField= attr; break; case htmlSelected: fSelectitem= fCurItem; //if (fCurField!=htmlOption) fCurField= attr; break; case htmlMultiple: fIsMultiple= true; fCurField= attr; break; case htmlSize: case htmlMaxlength: case htmlRows: case htmlCols: // case htmlName: // handled case htmlValue: //if (fCurField!=htmlOption) fLastField= fCurField; fCurField= attr; break; case htmlType: // record param fCurField= attr; fTypestore= (char*) MemFree(fTypestore); break; } } void DHTMLprocess::handleLinkAttr(short attr) { char buf[512]; switch (attr) { case htmlAnchor: if (fTurnOn) { fAnchorLink= 0; fCurControl= attr; // DAMN, need to push/pop something here -- having style changes inside // anchor causes it to disappear now !!! PushStyle(); //PutLitCharWithStyle('['); // [] for debugging } else { fStyleRec.style.color= 0; // ?? fStyleRec.style.linkid= 0; //PutLitCharWithStyle(']'); // [] for debugging PopStyle(); fAnchorLink= 0; } break; case htmlHref: fCurField= attr; // store: ="url://bob.was/here" fURLstore= (char*) MemFree(fURLstore); break; case htmlName: fCurField= attr; // store: ="some name" fNamestore= (char*) MemFree(fNamestore); break; case htmlRel: fCurField= attr; //fNamestore= (char*) MemFree(fNamestore); break; case htmlRev: fCurField= attr; //fNamestore= (char*) MemFree(fNamestore); break; case htmlUrn: fCurField= attr; //fNamestore= (char*) MemFree(fNamestore); break; case htmlMethods: fCurField= attr; //fNamestore= (char*) MemFree(fNamestore); break; //case htmlTitle: // handled in other section !! } } void DHTMLprocess::handlePictAttr(short attr) { switch (attr) { case htmlImage: { // main tag fCurControl= attr; fCurField= attr; } break; case htmlImageSrc: // this is the URL to remote picture ?? fCurField= attr; // store: ="url://bob.was/here" fURLstore= (char*) MemFree(fURLstore); break; case htmlImageAlt: // text name for non-graphic clients? case htmlIsMap: case htmlAlign: fCurField= attr; break; } } #ifdef TESTDEF #define DEFAULTS() { DefaultParag(); DefaultStyle(); GetNlmFont(); } #else #define DEFAULTS() {} #endif void DHTMLprocess::handleParAttr(short attr) { switch (attr) { case htmlH1: if (fTurnOn) { PushStyle(); handleSpecialChar(htmlPage); DefaultStyle(); fParaFmt.just= 'c'; fParaFmt.spaceBefore= 20; fStyleRec.style.bold= true; fStyleRec.fontsize= 2 * kDefaultFontsize; } else { fParaFmt.spaceAfter= 10; PutLitCharWithStyle('\n'); NewParagraph(); fParaFmt.just= 'l'; fParaFmt.spaceBefore= 0; fParaFmt.spaceAfter= 0; PopStyle(); DEFAULTS(); } NewStyle(); break; case htmlH2: if (fTurnOn) { PushStyle(); PutLitCharWithStyle ('\n'); NewParagraph(); DefaultStyle(); fParaFmt.spaceBefore= 10; fStyleRec.style.bold= true; fStyleRec.fontsize= 6 + kDefaultFontsize; } else { fParaFmt.spaceAfter= 5; PutLitCharWithStyle ('\n'); NewParagraph(); fParaFmt.spaceBefore= 0; fParaFmt.spaceAfter= 0; PopStyle(); DEFAULTS(); } NewStyle(); break; case htmlH3: if (fTurnOn) { PushStyle(); PutLitCharWithStyle ('\n'); NewParagraph(); DefaultStyle(); fParaFmt.spaceBefore= 6; fStyleRec.style.italic= true; fStyleRec.fontsize= 6 + kDefaultFontsize; } else { fParaFmt.spaceAfter= 4; PutLitCharWithStyle ('\n'); NewParagraph(); fParaFmt.spaceBefore= 0; fParaFmt.spaceAfter= 0; PopStyle(); DEFAULTS(); } NewStyle(); break; case htmlH4: if (fTurnOn) { PushStyle(); PutLitCharWithStyle('\n'); NewParagraph(); DefaultStyle(); fStyleRec.style.bold= true; fStyleRec.fontsize= 2 + kDefaultFontsize; } else { fParaFmt.spaceAfter= 4; PutLitCharWithStyle('\n'); NewParagraph(); fParaFmt.spaceBefore= 0; fParaFmt.spaceAfter= 0; PopStyle(); DEFAULTS(); } NewStyle(); break; case htmlH5: if (fTurnOn) { PushStyle(); PutLitCharWithStyle('\n'); NewParagraph(); DefaultStyle(); fStyleRec.fontsize= 2 + kDefaultFontsize; //fStyleRec.style.italic= true; } else { fParaFmt.spaceAfter= 2; PutLitCharWithStyle('\n'); fParaFmt.spaceBefore= 0; fParaFmt.spaceAfter= 0; PopStyle(); DEFAULTS(); } NewStyle(); break; case htmlH6: if (fTurnOn) { PushStyle(); PutLitCharWithStyle('\n'); NewParagraph(); DefaultStyle(); //fStyleRec.style.bold= true; } else { fParaFmt.spaceAfter= 2; PutLitCharWithStyle('\n'); PopStyle(); fParaFmt.spaceBefore= 0; fParaFmt.spaceAfter= 0; DEFAULTS(); } NewStyle(); break; case htmlAddress: if (fTurnOn) { PushStyle(); PutLitCharWithStyle('\n'); NewParagraph(); DefaultStyle(); fParaFmt.just= 'r'; fStyleRec.style.italic= true; } else { PutLitCharWithStyle('\n'); NewParagraph(); fParaFmt.just= 'l'; PopStyle(); DEFAULTS(); } NewStyle(); break; case htmlBlockquote: if (fTurnOn) { PushStyle(); PutLitCharWithStyle('\n'); fParaFmt.spaceBefore= 10; //fParaFmt.borderleft= TRUE; NewParagraph(); fParaFmt.leftInset += 30; fParaFmt.rightInset += 50; fStyleRec.style.italic= true; } else { fParaFmt.spaceAfter= 10; PutLitCharWithStyle('\n'); NewParagraph(); fParaFmt.spaceBefore= 0; fParaFmt.spaceAfter= 0; //fParaFmt.borderleft= false; fParaFmt.leftInset = MAX( 0, fParaFmt.leftInset-30); fParaFmt.rightInset= MAX( 0, fParaFmt.rightInset-50); PopStyle(); } NewStyle(); break; case htmlPreformat: fPreformat= fTurnOn; handleCharAttr(htmlFixedwidth); NewStyle(); break; case htmlLinewidth: // this is attrib of htmlPreformat break; // lists/tables ? case htmlDL: if (fTurnOn) { fParaFmt.leftInset += kDefTabstop; fParaFmt.firstInset -= kDefTabstop; fDLStyle= htmlDL; } else { PutLitCharWithStyle('\n'); NewParagraph(); fParaFmt.leftInset = MAX(0, fParaFmt.leftInset - kDefTabstop); fParaFmt.firstInset = MIN(0, fParaFmt.firstInset + kDefTabstop); } // attribs of htmlDL case htmlCompact: fDLStyle= htmlCompact; break; case htmlDT: PutLitCharWithStyle('\n'); NewParagraph(); fParaFmt.leftInset = MAX(0, fParaFmt.leftInset - kDefTabstop); fParaFmt.firstInset = MIN(0, fParaFmt.firstInset + kDefTabstop); break; case htmlDD: if (true) { //fDLStyle != htmlCompact) { PutLitCharWithStyle('\n'); NewParagraph(); fParaFmt.leftInset += kDefTabstop; fParaFmt.firstInset -= kDefTabstop; } PutStdCharWithStyle('\t'); break; } } void DHTMLprocess::handleListAttr(short attr) { switch (attr) { case htmlNumList: case htmlMenu: case htmlDir: case htmlBullList: fListType= attr; fListNum= 0; if (fTurnOn) { PutLitCharWithStyle('\n'); NewParagraph(); fParaFmt.leftInset += kDefTabstop; fParaFmt.firstInset -= kDefTabstop - 20; } else { PutLitCharWithStyle('\n'); NewParagraph(); fParaFmt.leftInset = MAX(0, fParaFmt.leftInset-kDefTabstop); fParaFmt.firstInset = MIN(0, fParaFmt.firstInset+kDefTabstop+20); PutLitCharWithStyle('\n'); NewParagraph(); } break; case htmlListItem: PutLitCharWithStyle('\n'); NewParagraph(); fListNum++; // count isn't nested, nor is fListType !! // !!? need push/pop for list vars !!!!!! if (fListType == htmlNumList) { char nums[30]; sprintf( nums, "%d\t", fListNum); PutLitStr( nums); } else { PutStdCharWithStyle( gGenCharMap[rtfSC_bullet]); //'¥' PutStdChar('\t'); } break; } } void DHTMLprocess::handleCharAttr(short attr) { switch (attr) { case htmlFixedwidth: //rtfFontNum: if (fTurnOn) { PushStyle(); fStyleRec.fontname= "courier"; fStyleRec.fontfamily= "Modern"; fStyleRec.fontsize= kDefaultFontsize; } else { PopStyle(); } NewStyle(); //(void) GetNlmFont(); break; case htmlSampleFont: case htmlUserFont: if (fTurnOn) { PushStyle(); fStyleRec.fontname= "helvetica"; fStyleRec.fontfamily= "Swiss"; fStyleRec.fontsize= kDefaultFontsize; } else { PopStyle(); } NewStyle(); //(void) GetNlmFont(); break; case htmlPlain: DefaultStyle(); NewStyle(); break; case htmlVarFont: //rtfSmallCaps: NewStyle(); fStyleRec.style.smallcaps= fTurnOn; break; case htmlEmphasis: case htmlBold: NewStyle(); fStyleRec.style.bold= fTurnOn; break; case htmlDefineFont: case htmlCiteFont: // ?? also use diff font?? case htmlItalic: NewStyle(); fStyleRec.style.italic= fTurnOn; break; case htmlMoreEmphasis: //rtfUnderline: NewStyle(); fStyleRec.style.bold= fTurnOn; if (fTurnOn) fStyleRec.style.underline = DRichStyle::kUnderline; else fStyleRec.style.underline= 0; break; case htmlInvisible: NewStyle(); fStyleRec.style.hidden= fTurnOn; break; } } void DHTMLprocess::handleSpecialChar(short code) { switch (code) { case htmlPar: fParaFmt.spaceAfter += 5; PutLitCharWithStyle('\n'); NewParagraph(); fParaFmt.spaceAfter -= 5; fLastChar= ' '; break; case htmlNewline: PutLitCharWithStyle('\n'); NewParagraph(); fLastChar= ' '; break; case htmlHBar: fParaFmt.borderstyle = DParagraph::kBorderSingle; fParaFmt.borderbottom = TRUE; PutLitCharWithStyle('\n'); PutLitChar(' '); NewParagraph(); fParaFmt.borderstyle = DParagraph::kNoBorder; fParaFmt.borderbottom = FALSE; PutLitCharWithStyle('\n'); NewParagraph(); fLastChar= ' '; break; case htmlPage: PutLitCharWithStyle ('\n'); fParaFmt.newPage= TRUE; NewParagraph(); fParaFmt.newPage= FALSE; fLastChar= ' '; break; case htmlTab: PutLitCharWithStyle('\t'); // tab isn't defined in HTML world... fLastChar= ' '; break; #if 0 case rtfSC_less: PutLitCharWithStyle('<'); break; case rtfSC_greater: PutLitCharWithStyle('>'); break; case rtfSC_quotedbl: PutLitCharWithStyle('"'); break; case rtfSC_ampersand: PutLitCharWithStyle('&'); break; #endif default: PutLitCharWithStyle( gGenCharMap[code]); fLastChar= gGenCharMap[code]; break; } }; HTMLKey DHTMLprocess::htmlKeys[] = { // document htmlDocAttr, htmlHTML, "html", kSlashStop, 0, htmlDocAttr, htmlTitle, "title", kSlashStop, 0, htmlDocAttr, htmlHead, "head", kSlashStop, 0, htmlDocAttr, htmlBody, "body", kSlashStop, 0, htmlDocAttr, htmlIsIndex, "isindex", kNoStop, 0, htmlDocAttr, htmlLink, "link", kNoStop, 0, htmlDocAttr, htmlNextID, "nextid", kNoStop, 0, htmlDocAttr, htmlBase, "base", kNoStop, 0, //htmlDocAttr, htmlHref, "href=", kNoStop, 0, htmlDocAttr, htmlComment, "!", kNoStop, 0, // anchors & links htmlLinkAttr, htmlAnchor, "a", kSlashStop, 0, htmlLinkAttr, htmlHref, "href", kNoStop, 0, htmlLinkAttr, htmlName, "name", kNoStop, 0, htmlLinkAttr, htmlRel, "rel", kNoStop, 0, htmlLinkAttr, htmlRev, "rev", kNoStop, 0, htmlLinkAttr, htmlUrn, "urn", kNoStop, 0, htmlLinkAttr, htmlMethods, "methods", kNoStop, 0, //htmlLinkAttr, htmlTitle, "title", kNoStop, 0, // forms tags htmlFormAttr, htmlForm, "form", kSlashStop, 0, htmlFormAttr, htmlInput, "input", kNoStop, 0, htmlFormAttr, htmlSelect, "select", kSlashStop, 0, htmlFormAttr, htmlTextarea, "textarea", kSlashStop, 0, htmlFormAttr, htmlValue, "value", kNoStop, 0, htmlFormAttr, htmlType, "type", kNoStop, 0, htmlFormAttr, htmlOption, "option", kNoStop, 0, htmlFormAttr, htmlAction, "action", kNoStop, 0, htmlFormAttr, htmlMethod, "method", kNoStop, 0, htmlFormAttr, htmlChecked, "checked", kNoStop, 0, htmlFormAttr, htmlSelected, "selected", kNoStop, 0, htmlFormAttr, htmlMultiple, "multiple", kNoStop, 0, htmlFormAttr, htmlSize, "size", kNoStop, 0, htmlFormAttr, htmlMaxlength, "maxlength", kNoStop, 0, htmlFormAttr, htmlRows, "rows", kNoStop, 0, htmlFormAttr, htmlCols, "cols", kNoStop, 0, // font styles htmlCharAttr, htmlBold, "b", kSlashStop, 0, htmlCharAttr, htmlEmphasis, "em", kSlashStop, 0, htmlCharAttr, htmlMoreEmphasis, "strong", kSlashStop, 0, htmlCharAttr, htmlItalic, "i", kSlashStop, 0, htmlCharAttr, htmlFixedwidth, "tt", kSlashStop, 0, // courier font !? htmlCharAttr, htmlFixedwidth, "code", kSlashStop, 0, // courier font !? htmlCharAttr, htmlSampleFont, "samp", kSlashStop, 0, htmlCharAttr, htmlUserFont, "kbd", kSlashStop, 0, htmlCharAttr, htmlVarFont, "var", kSlashStop, 0, htmlCharAttr, htmlDefineFont, "dfn", kSlashStop, 0, // bold htmlCharAttr, htmlCiteFont, "cite", kSlashStop, 0, // italic htmlCharAttr, htmlPlain, "plaintext", kSlashStop, 0, // paragraph styles htmlParAttr, htmlH1, "h1", kSlashStop, 0, htmlParAttr, htmlH2, "h2", kSlashStop, 0, htmlParAttr, htmlH3, "h3", kSlashStop, 0, htmlParAttr, htmlH4, "h4", kSlashStop, 0, htmlParAttr, htmlH5, "h5", kSlashStop, 0, htmlParAttr, htmlH6, "h6", kSlashStop, 0, htmlParAttr, htmlAddress, "address", kSlashStop, 0, htmlParAttr, htmlBlockquote, "blockquote", kSlashStop, 0, htmlParAttr, htmlPreformat, "pre", kSlashStop, 0, htmlParAttr, htmlLinewidth, "width", kNoStop, 0, htmlParAttr, htmlPreformat, "listing", kSlashStop, 0, htmlParAttr, htmlPreformat, "xmp", kSlashStop, 0, // lists/tables ? htmlParAttr, htmlDL, "dl", kSlashStop, 0, htmlParAttr, htmlCompact, "compact", kNoStop,0, htmlParAttr, htmlDT, "dt", kNoStop, 0, htmlParAttr, htmlDD, "dd", kNoStop, 0, // lists htmlListAttr, htmlBullList, "ul", kSlashStop, 0, htmlListAttr, htmlNumList, "ol", kSlashStop, 0, htmlListAttr, htmlMenu, "menu", kSlashStop, 0, htmlListAttr, htmlDir, "dir", kSlashStop, 0, htmlListAttr, htmlListItem, "li", kNoStop,0, // pictures htmlPictAttr, htmlImage, "img", kNoStop, 0, htmlPictAttr, htmlImageSrc, "src", kNoStop, 0, htmlPictAttr, htmlImageAlt, "alt", kNoStop, 0, htmlPictAttr, htmlAlign, "aln", kNoStop, 0, htmlPictAttr, htmlAlign, "align", kNoStop, 0, htmlPictAttr, htmlIsMap, "ismap", kNoStop, 0, // characters htmlSpecialChar, htmlPar, "p", kNoStop, 0, // parag htmlSpecialChar, htmlHBar, "hr", kNoStop, 0, // paragraph rule 0, -1, NULL, 0 }; HTMLKey DHTMLprocess::htmlAmperChars[] = { htmlSpecialChar, rtfSC_less, "lt;", kAmperChar, 0, htmlSpecialChar, rtfSC_greater, "gt;", kAmperChar, 0, htmlSpecialChar, rtfSC_ampersand, "amp;", kAmperChar, 0, htmlSpecialChar, rtfSC_quotedbl, "quot;", kAmperChar, 0, htmlSpecialChar, rtfSC_AE, "AElig;", kAmperChar, 0, htmlSpecialChar, rtfSC_Aacute, "Aacute;", kAmperChar, 0, htmlSpecialChar, rtfSC_Acircumflex, "Acirc;", kAmperChar, 0, htmlSpecialChar, rtfSC_Agrave, "Agrave;", kAmperChar, 0, htmlSpecialChar, rtfSC_Aring, "Aring;", kAmperChar, 0, htmlSpecialChar, rtfSC_Atilde, "Atilde;", kAmperChar, 0, htmlSpecialChar, rtfSC_Adieresis, "Auml;", kAmperChar, 0, htmlSpecialChar, rtfSC_Ccedilla, "Ccedil;", kAmperChar, 0, htmlSpecialChar, rtfSC_Eth, "ETH;", kAmperChar, 0, htmlSpecialChar, rtfSC_Eacute, "Eacute;", kAmperChar, 0, htmlSpecialChar, rtfSC_Ecircumflex, "Ecirc;", kAmperChar, 0, htmlSpecialChar, rtfSC_Egrave, "Egrave;", kAmperChar, 0, htmlSpecialChar, rtfSC_Edieresis, "Euml;", kAmperChar, 0, htmlSpecialChar, rtfSC_Iacute, "Iacute;", kAmperChar, 0, htmlSpecialChar, rtfSC_Icircumflex, "Icirc;", kAmperChar, 0, htmlSpecialChar, rtfSC_Igrave, "Igrave;", kAmperChar, 0, htmlSpecialChar, rtfSC_Idieresis, "Iuml;", kAmperChar, 0, htmlSpecialChar, rtfSC_Ntilde, "Ntilde;", kAmperChar, 0, htmlSpecialChar, rtfSC_Oacute, "Oacute;", kAmperChar, 0, htmlSpecialChar, rtfSC_Ocircumflex, "Ocirc;", kAmperChar, 0, htmlSpecialChar, rtfSC_Ograve, "Ograve;", kAmperChar, 0, htmlSpecialChar, rtfSC_Oslash, "Oslash;", kAmperChar, 0, htmlSpecialChar, rtfSC_Otilde, "Otilde;", kAmperChar, 0, htmlSpecialChar, rtfSC_Odieresis, "Ouml;", kAmperChar, 0, htmlSpecialChar, rtfSC_Thorn, "THORN;", kAmperChar, 0, htmlSpecialChar, rtfSC_Uacute, "Uacute;", kAmperChar, 0, htmlSpecialChar, rtfSC_Ucircumflex, "Ucirc;", kAmperChar, 0, htmlSpecialChar, rtfSC_Ugrave, "Ugrave;", kAmperChar, 0, htmlSpecialChar, rtfSC_Udieresis, "Uuml;", kAmperChar, 0, htmlSpecialChar, rtfSC_Yacute, "Yacute;", kAmperChar, 0, htmlSpecialChar, rtfSC_aacute, "aacute;", kAmperChar, 0, htmlSpecialChar, rtfSC_acircumflex, "acirc;", kAmperChar, 0, htmlSpecialChar, rtfSC_ae, "aelig;", kAmperChar, 0, htmlSpecialChar, rtfSC_agrave, "agrave;", kAmperChar, 0, htmlSpecialChar, rtfSC_aring, "aring;", kAmperChar, 0, htmlSpecialChar, rtfSC_atilde, "atilde;", kAmperChar, 0, htmlSpecialChar, rtfSC_adieresis, "auml;", kAmperChar, 0, htmlSpecialChar, rtfSC_ccedilla, "ccedil;", kAmperChar, 0, htmlSpecialChar, rtfSC_eacute, "eacute;", kAmperChar, 0, htmlSpecialChar, rtfSC_ecircumflex, "ecirc;", kAmperChar, 0, htmlSpecialChar, rtfSC_egrave, "egrave;", kAmperChar, 0, htmlSpecialChar, rtfSC_eth, "eth;", kAmperChar, 0, htmlSpecialChar, rtfSC_edieresis, "euml;", kAmperChar, 0, htmlSpecialChar, rtfSC_iacute, "iacute;", kAmperChar, 0, htmlSpecialChar, rtfSC_icircumflex, "icirc;", kAmperChar, 0, htmlSpecialChar, rtfSC_igrave, "igrave;", kAmperChar, 0, htmlSpecialChar, rtfSC_idieresis, "iuml;", kAmperChar, 0, htmlSpecialChar, rtfSC_ntilde, "ntilde;", kAmperChar, 0, htmlSpecialChar, rtfSC_oacute, "oacute;", kAmperChar, 0, htmlSpecialChar, rtfSC_ocircumflex, "ocirc;", kAmperChar, 0, htmlSpecialChar, rtfSC_ograve, "ograve;", kAmperChar, 0, htmlSpecialChar, rtfSC_oslash, "oslash;", kAmperChar, 0, htmlSpecialChar, rtfSC_otilde, "otilde;", kAmperChar, 0, htmlSpecialChar, rtfSC_odieresis, "ouml;", kAmperChar, 0, htmlSpecialChar, rtfSC_nothing, "szlig;", kAmperChar, 0, // ! no rtf equiv. htmlSpecialChar, rtfSC_thorn, "thorn;", kAmperChar, 0, htmlSpecialChar, rtfSC_uacute, "uacute;", kAmperChar, 0, htmlSpecialChar, rtfSC_ucircumflex, "ucirc;", kAmperChar, 0, htmlSpecialChar, rtfSC_ugrave, "ugrave;", kAmperChar, 0, htmlSpecialChar, rtfSC_udieresis, "uuml;", kAmperChar, 0, htmlSpecialChar, rtfSC_yacute, "yacute;", kAmperChar, 0, htmlSpecialChar, rtfSC_ydieresis, "yuml;", kAmperChar, 0, 0, -1, NULL, 0 };